import copy
import random
import traceback

from logger import logger
from sub_events.base_event import BaseEvent, CHECK_RESULT_FAIL, CHECK_RESULT_PASS

LOGGER = logger.CustomLogger()


class CheckComments(BaseEvent):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.event_name_zh: str = "检视意见检查"
        self.event_name_en: str = "Review Comments Check"

        self.addition_count_threshold = self.cfg.get("sub_events", {}).get("check_comment_count", {}).get("addition_count_threshold")
        self.comment_count_per_threshold = self.cfg.get("sub_events", {}).get("check_comment_count", {}).get("comment_count_per_threshold")
        self.tdd_addition_count_threshold = self.cfg.get("sub_events", {}).get("check_comment_count", {}).get("tdd_addition_count_threshold")
        self.tdd_comment_count_per_threshold = self.cfg.get("sub_events", {}).get("check_comment_count", {}).get("tdd_comment_count_per_threshold")

        self.addition_count = 0
        self.tdd_addition_count = 0
        self.expect_comments_count = 0
        self.actual_comments_count = 0
        self.expect_tdd_comments_count = 0
        self.actual_tdd_comments_count = 0

    def generate_table(self) -> str:
        check_result = [
            {
                "code type": "业务代码(business code)",
                "result": CHECK_RESULT_FAIL if self.actual_comments_count < self.expect_comments_count else CHECK_RESULT_PASS,
                "code additions": self.addition_count,
                "review comments count(actual/expect)": "%d/%d" % (
                    self.actual_comments_count, self.expect_comments_count),
            },
            {
                "code type": "测试代码(tdd code)",
                "result": CHECK_RESULT_FAIL if self.actual_tdd_comments_count < self.expect_tdd_comments_count else CHECK_RESULT_PASS,
                "code additions": self.tdd_addition_count,
                "review comments count(actual/expect)": "%d/%d" % (
                    self.actual_tdd_comments_count, self.expect_tdd_comments_count),
            },
        ]
        return self.generate_html_table(check_result, caption="%s(%s)" % (self.event_name_zh, self.event_name_en))

    def get_addition_count(self, pr_number):
        params = {'access_token': self.get_admin_token()}
        files = self.git_client.get_files(pr_number, params)
        for f in files:
            if "unittest" in f['filename']:
                self.tdd_addition_count += int(f.get('additions', 0))
            elif "examples" not in f['filename']:
                self.addition_count += int(f.get('additions', 0))

    def pre_execute(self) -> bool:
        self.get_addition_count(self.hook.pr_number)
        return self.addition_count >= self.addition_count_threshold / 4 or \
            self.tdd_addition_count >= self.tdd_addition_count_threshold / 4

    def check_comment_count(self):
        tokens = copy.deepcopy(self.cfg.get("sub_events", {}).get("check_comment_count", {}).get("tokens", []))
        token = None
        try_time = 0
        while try_time < 3:
            try:
                choice_count = len(tokens)
                # 从tokens中随机选择一个token访问，防止出现403
                index = random.randint(0, choice_count-1)
                token = tokens[index]
                params = {
                    'Authorization': f'token {token}',
                    "comment_type": "diff_comment",
                    "per_page": 100
                }
                response = self.git_client.get_comments(self.hook.pr_number, params)
                for comment in response:
                    if "unittest" in comment["path"]:
                        self.actual_tdd_comments_count += 1
                    else:
                        self.actual_comments_count += 1
                self.failed = self.actual_comments_count < self.expect_comments_count or self.actual_tdd_comments_count < self.expect_tdd_comments_count
                return
            except Exception as e:
                stack_str = traceback.format_exc()
                if token in tokens:
                    tokens.remove(token)
                try_time += 1
                LOGGER.error(f"[{self.hook.pr_number}] get comments failed, details: {str(e)}, traceback:\n{stack_str}")

    def execute(self) :
        """
        检查检视意见数量是否达标
        """
        self.expect_comments_count = self.addition_count // self.addition_count_threshold * self.comment_count_per_threshold
        if self.addition_count_threshold / 4 <= self.addition_count < self.addition_count_threshold:
            self.expect_comments_count = 1
        self.expect_tdd_comments_count = self.tdd_addition_count // self.tdd_addition_count_threshold * self.tdd_comment_count_per_threshold
        if self.tdd_addition_count_threshold / 4 <= self.tdd_addition_count < self.tdd_addition_count_threshold:
            self.expect_tdd_comments_count = 1
        if self.expect_comments_count > 20:
            self.expect_comments_count = 20
        if self.expect_tdd_comments_count > 20:
            self.expect_tdd_comments_count = 20
        self.check_comment_count()
        if self.failed:
            table = self.generate_table()
            suggestion = """检视意见数量未达标（详情见上述表格），请联系组内成员积极进行代码检视。\n"""
            suggestion += """The count of review comments falls short of the target (as detailed in the table above).
            Please contact your team to actively review your code.
                            """
            self.comment = table + "\n\n" + suggestion
